#ifndef _TRANSITION_H_
#define _TRANSITION_H_

#include <vector>
#include "math/counter.h"
#include "num/named_set.h"
#include "util/delegate.h"
#include "ui/ui_widget.h"
#include "ui/ui_mover.h"

namespace gameflow
{
class TransitionManager;
class	GameTransition
{
public:
	typedef util::Delegate1<GameTransition*>	TransitionEvent;
#define	TRANSITION_DELEGATE(CLASS_ID, FUNCTION_POINTER) UTIL_MAKE_DELEGATE_M(gameflow::GameTransition::TransitionEvent, this, CLASS_ID, FUNCTION_POINTER)

	
					GameTransition(const std::string& Name);
	virtual			~GameTransition();
	virtual void	Render();
	virtual void	Tick(float dt);
	void			SetOwner(TransitionManager* pOwner) { m_pOwner = pOwner; };
	bool			IsOver() { return m_Timer.IsReady() && m_TimeOut.IsReady(); };
	float			GetProg() { if (m_Reverse) return 1.0f-m_Timer.GetProgress(); else return m_Timer.GetProgress(); };
	void			SetReverse(bool b) { m_Reverse = b; };
	void			SetScript(const std::string& Script) { m_OnDone = Script; };
	void			SetFunctor(TransitionEvent	Func) { m_OnComplete = Func; };

	void			SetColor(	unsigned char	R, unsigned char	G, unsigned char	B) { m_R = R; m_G = G; m_B = B; };

protected:
	unsigned char	m_R, m_G, m_B;
	math::Counter	m_Timer;
	math::Counter	m_TimeOut;
	TransitionEvent	m_OnComplete;
	std::string		m_OnDone;
	std::string		m_Name;
	bool			m_Reverse;
	TransitionManager* m_pOwner;
};
	
class	TransitionManager
{
public:
	TransitionManager();
	~TransitionManager();
	void		Tick(float dt);
	void		Render();
	bool		IsRunning();
	void		GetTransition(const std::string& Name, GameTransition* &pFrom, GameTransition* &pTo);
	void		StartTransition(const std::string& Name, const std::string& To, const std::string& Script, GameTransition::TransitionEvent	Event);
	void		SetupTransitionDg(ui::UIWidget* pWidget, const std::string& ToState, const std::string& Sound = "", GameTransition::TransitionEvent		OnStart=NULL, GameTransition::TransitionEvent	OnFinish=NULL);
	void		SetImage(const std::string& Name, const math::Vec2& UV1, const math::Vec2& UV2)  { m_Sprite.Create(Name); m_UV1 = UV1; m_UV2 = UV2;};
	void			SetColor(	unsigned char	R, unsigned char	G, unsigned char	B) { m_R = R; m_G = G; m_B = B; };
	
	GameTransition*		GetFrom() { return m_pFrom; };
	GameTransition*		GetTo() { return m_pTo; };
	const math::Vec2&	GetUV1() const { return m_UV1; };
	const math::Vec2&	GetUV2() const { return m_UV2; };
	typedef GameTransition* (*TransitionCB)(const std::string&);
	void				RegisterTransition(const std::string& Name, TransitionCB pCreator);
	void				DropTransition(const std::string& Name);
	void				SetTexture();

protected:
	unsigned char	m_R, m_G, m_B;
	struct		TransitionCreator
	{
		TransitionCB		pCB;
		std::string				Name;
	};
	num::NamedSet<TransitionCreator*>		m_Creators;
	// a sequence is a FROM, Change State, TO

	GameTransition*				m_pFrom;
	GameTransition*				m_pTo;
	std::string					m_NextState;

	void DELEGATE_CALL			OnStateTransitionClicked(ui::UIWidget::WIDGET_EVENT Event, ui::UIWidget* pWidget);

	struct				UITransition
	{
		std::string							ToState;		// start the switch to which state?
		std::string							PlaySound;		// play a sound on the way out?
		std::string							TransitionEffect;	// do we have a specific transition in mind
		ui::UIWidget*						pSourceWidget;	// used to determine which transition to call
		GameTransition::TransitionEvent		OnStart, OnFinish;
	};
	std::vector<UITransition*>		m_Transitions;
	ui::UISprite					m_Sprite;
	math::Vec2						m_UV1, m_UV2;
};

};	//namespace gameflow

#endif // _TRANSITION_H_